﻿using System;
using System.Collections.Generic;
using System.Linq;
using BCCommon;
using BCCommon.Extensions;
using BCCommon.OAEnums;
using BCEntity;
using BCData.OA.Attendance.AttendanceClass;
using BCEntity.OA.Attendance.AttendanceClassDate;
using BCEntity.OA.Attendance.AttendanceGroup;
using BCEntity.OA.Attendance.AttendanceLocation;
using BCEntity.OA.Attendance.AttendancePlan;
using BCEntity.OA.Attendance.AttendanceWiFi;
using BCData.OA.Attendance.AttendanceClassDate;
using BCData.OA.Attendance.AttendanceGroup;
using BCDto.MySql.Admin;
using BCDto.OA.Attendance.AttendanceClass;
using BCDto.OA.Attendance.AttendanceGroup;
using BCDto.OA.Attendance.AttendanceMode;
using BCDto.OA.Attendance.AttendancePlan;
using BCService.AdminService;
using BCService.OA.Attendance.AttendanceLocation;
using BCService.OA.Attendance.AttendanceRemedyRules;
using BCService.OA.Attendance.AttendanceWiFi;
using BCService.Utils;
using BCService.WebDomainService.DepartmentService;
using BCService.WebDomainService.DepartmentStaffService;

namespace BCService.OA.Attendance.AttendanceGroup
{
    /// <summary>
    /// 考勤组信息
    /// </summary>
    public class AttendanceGroupService : IAttendanceGroupService
    {
        private readonly IAttendanceGroupData attendanceGroupData;
        private readonly IAttendanceClassData attendanceClassData;
        private readonly IDepartmentService departmentService;
        private readonly IDepartmentStaffService departmentStaffService;
        private readonly IAdminService adminService;
        private readonly IAttendanceLocationService attendanceLocationService;
        private readonly IAttendanceWiFiService attendanceWiFiService;
        private readonly IRedisService redisService;
        private readonly IAttendanceRemedyRulesService remedyRulesService;
        private readonly IAttendanceClassDateData attendanceClassDateData;

        public AttendanceGroupService(IAttendanceGroupData attendanceGroupData, IAttendanceClassData attendanceClassData, IDepartmentService departmentService, IAdminService adminService, IAttendanceLocationService attendanceLocationService, IAttendanceWiFiService attendanceWiFiService, IRedisService redisService, IDepartmentStaffService departmentStaffService, IAttendanceRemedyRulesService remedyRulesService, IAttendanceClassDateData attendanceClassDateData)
        {
            this.attendanceGroupData = attendanceGroupData;
            this.attendanceClassData = attendanceClassData;
            this.departmentService = departmentService;
            this.adminService = adminService;
            this.attendanceLocationService = attendanceLocationService;
            this.attendanceWiFiService = attendanceWiFiService;
            this.redisService = redisService;
            this.departmentStaffService = departmentStaffService;
            this.remedyRulesService = remedyRulesService;
            this.attendanceClassDateData = attendanceClassDateData;
        }

        #region 新增操作


        /// <summary>
        /// 新创建固定考勤组
        /// </summary>
        /// <param name="admin">当前管理员</param>
        /// <param name="dto">考勤信息</param>
        /// <returns></returns>
        public AttendanceGroupDto CreateFixedGroup(AdminDto admin, AttendanceFixedGroupRequestDto dto)
        {
            AttendanceGroupEntity entity = dto.As<AttendanceGroupEntity>();
            entity.AdminId = admin.AdminId;
            entity.CompanyId = admin.CompanyId;
            entity.AdminName = admin.FullName;
            entity.Type = AttendanceType.FIXED.ToString();

            List<AttendanceGroupFixedEntity> fixedEntities = new List<AttendanceGroupFixedEntity>();
            if (!dto.Settings.Any())
            {
                throw new ArgumentException("工作日设置信息不能为空。");
            }
            foreach (var item in dto.Settings)
            {
                fixedEntities.Add(new AttendanceGroupFixedEntity
                {
                    ClassId = item.ClassId,
                    WeekDay = item.WeekDay
                });
            }
            if (dto.DepartmentIds.Length <= 0)
            {
                throw new ArgumentException("请选择部门信息。");
            }
            if (!dto.Locations.Any() && !dto.Wifi.Any())
            {
                throw new ArgumentException("考勤方式至少需满足一个。");
            }
            if (!dto.EffectiveDate.HasValue)
            {
                throw new ArgumentException("请设置一个生效日期。");
            }
            //校验部门是否已存在于考勤组
            foreach (var departmentId in dto.DepartmentIds)
            {
                if (attendanceGroupData.CheckDepartmentIsExist(Convert.ToInt32(departmentId), admin.CompanyId).GetAwaiter().GetResult())
                {
                    throw new ArgumentException($"该部门:{departmentId} 已存在于考勤组，不能重复新增。");
                }
            }
            List<string> modeIdList = new List<string>();
            if (dto.Locations.Any())
            {
                modeIdList.Add(dto.Locations.Select(s => s.ModeId.ToString()).Distinct().First());
            }
            if (dto.Wifi.Any())
            {
                modeIdList.Add(dto.Wifi.Select(s => s.ModeId.ToString()).Distinct().First());
            }
            entity.DepartmentIds = string.Join(",", dto.DepartmentIds);
            entity.ManagerIds = string.Join(",", dto.ManagerIds);
            entity.IgnoreMemberIds = string.Join(",", dto.IgnoreMemberIds);
            entity.ModeIds = string.Join(",", modeIdList);
            entity.RemedyRuleId = remedyRulesService.GetFirstDefault().RemedyRuleId;
            entity.EffectiveDate = dto.EffectiveDate.Value;
            List<AttendanceLocationEntity> locationEntities = dto.Locations.As<List<AttendanceLocationEntity>>();
            List<AttendanceWiFiEntity> wiFiEntities = dto.Wifi.As<List<AttendanceWiFiEntity>>();
            return attendanceGroupData.InsertAsync(entity, locationEntities, wiFiEntities, fixedEntities).GetAwaiter().GetResult().As<AttendanceGroupDto>();
        }

        /// <summary>
        /// 新创建自由时间考勤组
        /// </summary>
        /// <param name="admin">当前管理员</param>
        /// <param name="dto">考勤信息</param>
        /// <returns></returns>
        public AttendanceGroupDto CreateNoneGroup(AdminDto admin, AttendanceNoneGroupRequestDto dto)
        {
            AttendanceGroupEntity entity = dto.As<AttendanceGroupEntity>();
            entity.AdminId = admin.AdminId;
            entity.CompanyId = admin.CompanyId;
            entity.AdminName = admin.FullName;
            entity.Type = AttendanceType.NONE.ToString();

            if (!dto.Locations.Any() && !dto.Wifi.Any())
            {
                throw new ArgumentException("考勤方式至少需满足一个。");
            }
            if (!dto.EffectiveDate.HasValue)
            {
                throw new ArgumentException("请设置一个生效日期。");
            }
            if (dto.DepartmentIds.Length <= 0)
            {
                throw new ArgumentException("请选择部门信息。");
            }
            //校验部门是否已存在于考勤组
            foreach (var departmentId in dto.DepartmentIds)
            {
                if (attendanceGroupData.CheckDepartmentIsExist(Convert.ToInt32(departmentId), admin.CompanyId).GetAwaiter().GetResult())
                {
                    throw new ArgumentException($"该部门:{departmentId} 已存在于考勤组，不能重复新增。");
                }
            }

            List<string> modeIdList = new List<string>();
            if (dto.Locations.Any())
            {
                modeIdList.Add(dto.Locations.Select(s => s.ModeId.ToString()).Distinct().First());
            }
            if (dto.Wifi.Any())
            {
                modeIdList.Add(dto.Wifi.Select(s => s.ModeId.ToString()).Distinct().First());
            }
            entity.DepartmentIds = string.Join(",", dto.DepartmentIds);
            entity.ManagerIds = string.Join(",", dto.ManagerIds);
            entity.IgnoreMemberIds = string.Join(",", dto.IgnoreMemberIds);
            entity.ModeIds = string.Join(",", modeIdList);
            entity.RemedyRuleId = remedyRulesService.GetFirstDefault().RemedyRuleId;
            entity.EffectiveDate = dto.EffectiveDate.Value;
            List<AttendanceLocationEntity> locationEntities = dto.Locations.As<List<AttendanceLocationEntity>>();
            List<AttendanceWiFiEntity> wiFiEntities = dto.Wifi.As<List<AttendanceWiFiEntity>>();
            return attendanceGroupData.InsertAsync(entity, locationEntities, wiFiEntities).GetAwaiter().GetResult().As<AttendanceGroupDto>();

        }
        /// <summary>
        /// 新创建排班制考勤组
        /// </summary>
        /// <param name="admin">当前管理员</param>
        /// <param name="dto">考勤信息</param>
        /// <returns></returns>
        public AttendanceGroupDto CreateTurnGroup(AdminDto admin, AttendanceTurnGroupRequestDto dto)
        {
            AttendanceGroupEntity entity = dto.As<AttendanceGroupEntity>();
            entity.AdminId = admin.AdminId;
            entity.CompanyId = admin.CompanyId;
            entity.AdminName = admin.FullName;
            entity.Type = AttendanceType.TURN.ToString();
            if (dto.CycleDays <= 0)
            {
                throw new ArgumentException("周期天数不能为空。");
            }
            if (dto.CycleDays > 31)
            {
                throw new ArgumentException("周期天数不能超过31天。");
            }
            if (!dto.Plans.Any())
            {
                throw new ArgumentException("排班信息不能为空");
            }
            if (dto.DepartmentIds.Length <= 0)
            {
                throw new ArgumentException("请选择部门信息。");
            }
            if (!dto.Locations.Any() && !dto.Wifi.Any())
            {
                throw new ArgumentException("考勤方式至少需满足一个。");
            }
            if (!dto.EffectiveDate.HasValue)
            {
                throw new ArgumentException("请设置一个生效日期。");
            }
            //校验部门是否已存在于考勤组
            foreach (var departmentId in dto.DepartmentIds)
            {
                if (attendanceGroupData.CheckDepartmentIsExist(Convert.ToInt32(departmentId), admin.CompanyId).GetAwaiter().GetResult())
                {
                    throw new ArgumentException($"该部门:{departmentId} 已存在于考勤组，不能重复新增。");
                }
            }
            List<string> modeIdList = new List<string>();
            if (dto.Locations.Any())
            {
                modeIdList.Add(dto.Locations.Select(s => s.ModeId.ToString()).Distinct().First());
            }
            if (dto.Wifi.Any())
            {
                modeIdList.Add(dto.Wifi.Select(s => s.ModeId.ToString()).Distinct().First());
            }
            entity.PlanClassIds = string.Join(",", dto.PlanClassIds);
            entity.DepartmentIds = string.Join(",", dto.DepartmentIds);
            entity.ManagerIds = string.Join(",", dto.ManagerIds);
            entity.IgnoreMemberIds = string.Join(",", dto.IgnoreMemberIds);
            entity.ModeIds = string.Join(",", modeIdList);
            entity.EffectiveDate = dto.EffectiveDate.Value;
            entity.RemedyRuleId = remedyRulesService.GetFirstDefault().RemedyRuleId;
            List<AttendanceLocationEntity> locationEntities = dto.Locations.As<List<AttendanceLocationEntity>>();
            List<AttendanceWiFiEntity> wiFiEntities = dto.Wifi.As<List<AttendanceWiFiEntity>>();
            List<AttendancePlanEntity> planEntities = dto.Plans.As<List<AttendancePlanEntity>>();
            return attendanceGroupData.InsertAsync(entity, locationEntities, wiFiEntities, null, planEntities).GetAwaiter().GetResult().As<AttendanceGroupDto>();
        }


        //// <summary>
        /// 取得某月的最后一天
        /// </summary>
        /// <param name="datetime">要取得月份最后一天的时间</param>
        /// <returns></returns>
        private DateTime LastDayOfMonth(DateTime datetime) => datetime.AddDays(1 - datetime.Day).AddMonths(1).AddDays(-1);
        #endregion

        #region 删除操作
        /// <summary>
        /// 删除指定的考勤组信息
        /// </summary>
        /// <param name="admin">当前管理员</param>
        /// <param name="groupId"></param>
        /// <returns></returns>

        public int Delete(AdminDto admin, long groupId)
        {
            var result = attendanceGroupData.DeleteAsync(groupId, admin.FullName).GetAwaiter().GetResult();
            if (result > 0)
            {
                string key = string.Format("{0}:GroupId={1}", EntityNameConst.AttendanceGroupEntity, groupId);
                redisService.Delete(key);
            }
            return result;
        }


        #endregion

        #region 修改操作

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="admin"></param>
        /// <param name="groupId"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        public AttendanceGroupDto UpdateFixedGroup(AdminDto admin, long groupId, AttendanceFixedGroupRequestDto dto)
        {
            if (!attendanceGroupData.CheckIsExist(groupId).GetAwaiter().GetResult())
            {
                throw new ArgumentException("考勤组信息不存在。");
            }
            if (dto.DepartmentIds.Length <= 0)
            {
                throw new ArgumentException("请选择部门信息。");
            }
            var entity = dto.As<AttendanceGroupEntity>();
            entity.AdminId = admin.AdminId;
            entity.AdminName = admin.FullName;
            entity.GroupId = groupId;
            entity.ModifierId = admin.AdminId;
            entity.ModifierName = admin.FullName;
            entity.CompanyId = admin.CompanyId;
            entity.Type = AttendanceType.FIXED.ToString();

            List<AttendanceGroupFixedEntity> fixedEntities = new List<AttendanceGroupFixedEntity>();
            if (!dto.Settings.Any())
            {
                throw new ArgumentException("工作日设置信息不能为空。");
            }
            foreach (var item in dto.Settings)
            {
                fixedEntities.Add(new AttendanceGroupFixedEntity
                {
                    ClassId = item.ClassId,
                    WeekDay = item.WeekDay
                });
            }
            if (!dto.Locations.Any() && !dto.Wifi.Any())
            {
                throw new ArgumentException("考勤方式至少需满足一个。");
            }
            if (!dto.EffectiveDate.HasValue)
            {
                throw new ArgumentException("请设置一个生效日期。");
            }
            List<string> modeIdList = new List<string>();
            if (dto.Locations.Any())
            {
                modeIdList.Add(dto.Locations.Select(s => s.ModeId.ToString()).Distinct().First());
            }
            if (dto.Wifi.Any())
            {
                modeIdList.Add(dto.Wifi.Select(s => s.ModeId.ToString()).Distinct().First());
            }
            entity.DepartmentIds = string.Join(",", dto.DepartmentIds);
            entity.ManagerIds = string.Join(",", dto.ManagerIds);
            entity.IgnoreMemberIds = string.Join(",", dto.IgnoreMemberIds);
            entity.ModeIds = string.Join(",", modeIdList);
            entity.EffectiveDate = dto.EffectiveDate.Value;
            List<AttendanceLocationEntity> locationEntities = dto.Locations.As<List<AttendanceLocationEntity>>();
            List<AttendanceWiFiEntity> wiFiEntities = dto.Wifi.As<List<AttendanceWiFiEntity>>();
            var result = attendanceGroupData.UpdateAsync(entity, locationEntities, wiFiEntities, fixedEntities).GetAwaiter().GetResult().As<AttendanceGroupDto>();
            if (result.IsNotNull())
            {
                string key = string.Format("{0}:GroupId={1}", EntityNameConst.AttendanceGroupEntity, groupId);
                redisService.Delete(key);
            }
            return result;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="admin"></param>
        /// <param name="groupId"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        public AttendanceGroupDto UpdateNoneGroup(AdminDto admin, long groupId, AttendanceNoneGroupRequestDto dto)
        {
            if (dto.DepartmentIds.Length <= 0)
            {
                throw new ArgumentException("请选择部门信息。");
            }
            if (!attendanceGroupData.CheckIsExist(groupId).GetAwaiter().GetResult())
            {
                throw new ArgumentException("考勤组信息不存在。");
            }
            var entity = dto.As<AttendanceGroupEntity>();
            entity.AdminId = admin.AdminId;
            entity.AdminName = admin.FullName;
            entity.GroupId = groupId;
            entity.ModifierId = admin.AdminId;
            entity.ModifierName = admin.FullName;
            entity.CompanyId = admin.CompanyId;
            entity.AdminName = admin.FullName;
            entity.Type = AttendanceType.NONE.ToString();

            if (!dto.Locations.Any() && !dto.Wifi.Any())
            {
                throw new ArgumentException("考勤方式至少需满足一个。");
            }
            if (!dto.EffectiveDate.HasValue)
            {
                throw new ArgumentException("请设置一个生效日期。");
            }

            List<string> modeIdList = new List<string>();
            if (dto.Locations.Any())
            {
                modeIdList.Add(dto.Locations.Select(s => s.ModeId.ToString()).Distinct().First());
            }
            if (dto.Wifi.Any())
            {
                modeIdList.Add(dto.Wifi.Select(s => s.ModeId.ToString()).Distinct().First());
            }
            entity.DepartmentIds = string.Join(",", dto.DepartmentIds);
            entity.ManagerIds = string.Join(",", dto.ManagerIds);
            entity.IgnoreMemberIds = string.Join(",", dto.IgnoreMemberIds);
            entity.ModeIds = string.Join(",", modeIdList);
            entity.EffectiveDate = dto.EffectiveDate.Value;
            List<AttendanceLocationEntity> locationEntities = dto.Locations.As<List<AttendanceLocationEntity>>();
            List<AttendanceWiFiEntity> wiFiEntities = dto.Wifi.As<List<AttendanceWiFiEntity>>();
            var result = attendanceGroupData.UpdateAsync(entity, locationEntities, wiFiEntities).GetAwaiter().GetResult().As<AttendanceGroupDto>();
            if (result.IsNotNull())
            {
                attendanceGroupData.UpdateEffectiveDateAsync(entity.GroupId, entity.EffectiveDate).GetAwaiter().GetResult();
                string key = string.Format("{0}:GroupId={1}", EntityNameConst.AttendanceGroupEntity, groupId);
                redisService.Delete(key);
            }
            return result;
        }



        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="admin"></param>
        /// <param name="groupId"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        public AttendanceGroupDto UpdateTurnGroup(AdminDto admin, long groupId, AttendanceTurnGroupRequestDto dto)
        {
            if (dto.DepartmentIds.Length <= 0)
            {
                throw new ArgumentException("请选择部门信息。");
            }
            if (!attendanceGroupData.CheckIsExist(groupId).GetAwaiter().GetResult())
            {
                throw new ArgumentException("考勤组信息不存在。");
            }
            var entity = dto.As<AttendanceGroupEntity>();
            entity.AdminId = admin.AdminId;
            entity.AdminName = admin.FullName;
            entity.GroupId = groupId;
            entity.ModifierId = admin.AdminId;
            entity.AdminName = admin.FullName;
            entity.ModifierName = admin.FullName;
            entity.CompanyId = admin.CompanyId;
            entity.Type = AttendanceType.TURN.ToString();
            if (dto.CycleDays <= 0)
            {
                throw new ArgumentException("周期天数不能为空。");
            }
            if (dto.CycleDays > 31)
            {
                throw new ArgumentException("周期天数不能超过31天。");
            }
            if (!dto.Plans.Any())
            {
                throw new ArgumentException("排班周期不能为空。");
            }
            if (!dto.Locations.Any() && !dto.Wifi.Any())
            {
                throw new ArgumentException("考勤方式至少需满足一个。");
            }
            if (!dto.EffectiveDate.HasValue)
            {
                throw new ArgumentException("请设置一个生效日期。");
            }
            List<string> modeIdList = new List<string>();
            if (dto.Locations.Any())
            {
                modeIdList.Add(dto.Locations.Select(s => s.ModeId.ToString()).Distinct().First());
            }
            if (dto.Wifi.Any())
            {
                modeIdList.Add(dto.Wifi.Select(s => s.ModeId.ToString()).Distinct().First());
            }
            entity.DepartmentIds = string.Join(",", dto.DepartmentIds);
            entity.ManagerIds = string.Join(",", dto.ManagerIds);
            entity.IgnoreMemberIds = string.Join(",", dto.IgnoreMemberIds);
            entity.ModeIds = string.Join(",", modeIdList);
            entity.EffectiveDate = dto.EffectiveDate.Value;
            List<AttendanceLocationEntity> locationEntities = dto.Locations.As<List<AttendanceLocationEntity>>();
            List<AttendanceWiFiEntity> wiFiEntities = dto.Wifi.As<List<AttendanceWiFiEntity>>();
            List<AttendancePlanEntity> planEntities = dto.Plans.As<List<AttendancePlanEntity>>();
            var result = attendanceGroupData.UpdateAsync(entity, locationEntities, wiFiEntities, null, planEntities).GetAwaiter().GetResult().As<AttendanceGroupDto>();
            if (result.IsNotNull())
            {
                string key = string.Format("{0}:GroupId={1}", EntityNameConst.AttendanceGroupEntity, groupId);
                redisService.Delete(key);
            }
            return result;
        }

        #endregion

        #region 查询操作

        #region 员工端查询考勤组信息

        /// <summary>
        /// 员工端查询考勤组信息
        /// </summary>
        /// <param name="groupId"></param>
        /// <returns></returns>
        public AttendanceGroupViewForStaffAppDto GetByGroupIdForStaffApp(long groupId)
        {
            string key = string.Format("{0}:GroupId={1}", EntityNameConst.AttendanceGroupEntity, groupId);

            var entity = this.redisService.TryGet(key, () => this.GetAttendanceGroupViewForStaffAppByGroupId(groupId), TimeSpan.FromHours(2));
            return entity.As<AttendanceGroupViewForStaffAppDto>();

        }

        private AttendanceGroupViewForStaffAppDto GetAttendanceGroupViewForStaffAppByGroupId(long groupId)
        {
            AttendanceGroupViewForStaffAppDto viewDto = new AttendanceGroupViewForStaffAppDto();
            var item = attendanceGroupData.GetEntityAsync(groupId).GetAwaiter().GetResult().As<AttendanceGroupDto>();
            if (item != null)
            {
                viewDto.GroupInfo = item;
                switch (item.Type.As<AttendanceType>())
                {
                    case AttendanceType.FIXED:
                        var fixedSettings = attendanceGroupData.GetGroupFixedByGroupId(groupId).GetAwaiter().GetResult().As<List<AttendanceGroupFixedViewDto>>();
                        viewDto.ClassIds.AddRange(fixedSettings.Where(s => s.ClassId > 0).GroupBy(s => s.ClassId).Select(d => d.Key));
                        foreach (var id in viewDto.ClassIds)
                        {
                            var classInfo = attendanceClassData.GetEntityAsync(id).GetAwaiter().GetResult();
                            viewDto.ClassList.Add(string.Format("{0} {1} {2}",
                             string.Join("、", fixedSettings.Where(s => s.ClassId == id).Select(d => d.WeekDay)),
                             classInfo.ClassName,
                             classInfo.WeekDay));
                            AttendanceClassViewDto view = new AttendanceClassViewDto
                            {
                                ClassId = classInfo.ClassId,
                                ClassName = classInfo.ClassName
                            };
                            var settings = attendanceClassData.GetAttendanceClassWithSettings(id).GetAwaiter().GetResult();
                            foreach (var s in settings.Where(s => s.ClassId == id))
                            {
                                view.Sections.Add(new { s.Start, s.End });
                            }
                            viewDto.WorkDayList.Add(view);
                        }
                        viewDto.ClassList.Add(string.Format("{0} {1}",
                            string.Join("、", fixedSettings.Where(s => s.ClassId == 0).GroupBy(s => s.ClassId).Select(d => d.First().WeekDay)),
                            "休息"));

                        break;
                    case AttendanceType.NONE:
                        viewDto.ClassList.Add("不设置班次，随时打卡");
                        break;
                    case AttendanceType.TURN:
                        var plans = attendanceGroupData.GettGroupPlanByGroupId(item.GroupId).GetAwaiter().GetResult().As<List<AttendancePlanViewDto>>();
                        viewDto.ClassIds.AddRange(plans.Where(s => s.ClassId > 0).GroupBy(s => s.ClassId).Select(d => d.Key));
                        foreach (var id in viewDto.ClassIds)
                        {
                            var planItem = plans.First(s => s.ClassId == id);
                            viewDto.ClassList.Add(string.Format("{0} {1}", planItem.ClassName, planItem.ClassWeekDay));
                            var settings = attendanceClassData.GetAttendanceClassWithSettings(id).GetAwaiter().GetResult();
                            AttendanceClassViewDto view = new AttendanceClassViewDto
                            {
                                ClassId = planItem.ClassId,
                                ClassName = planItem.ClassName
                            };
                            foreach (var s in settings.Where(s => s.ClassId == planItem.ClassId))
                            {
                                view.Sections.Add(new { s.Start, s.End });
                            }
                            viewDto.WorkDayList.Add(view);
                        }
                        List<AttendanceClassDateEntity> dates = GenerateClassDates(item, plans);
                        foreach (var date in dates)
                        {
                            var plan = plans.First(p => p.ClassId == date.ClassId);
                            viewDto.Dates.Add(new AttendancePlanDate
                            {
                                DayOfWeek = date.DayOfWeek,
                                TimeStamp = DateTime.Parse(string.Format("{0}-{1}-{2}", date.Year, date.Month, date.Day)),
                                ClassId = date.ClassId,
                                ClassName = date.ClassName,
                                ClassWeekDay = plan.ClassWeekDay,
                                Sections = viewDto.WorkDayList.First(s => s.ClassId == date.ClassId).Sections
                            });
                        }
                        break;
                    default:
                        break;
                }

                #region 打卡方式
                if (item.ModeIds.IsNotNull())
                {
                    string[] modes = item.ModeIds.Split(',');
                    AttendanceModeViewDto modeView = new AttendanceModeViewDto();
                    foreach (var mode in modes)
                    {
                        if (mode.ToString() == CheckInMode.Location.ToString())
                        {
                            modeView.Locations = attendanceLocationService.GetListByModeIdAndGroupId(item.GroupId);

                        }
                        if (mode.ToString() == CheckInMode.Wifi.ToString())
                        {
                            modeView.WifiList = attendanceWiFiService.GetListByModeIdAndGroupId(item.GroupId);
                        }

                        viewDto.Modes = modeView;
                    }
                }
                #endregion

                #region 补卡规则信息
                viewDto.RemedyRule = remedyRulesService.GetById(item.RemedyRuleId);
                #endregion
            }
            return viewDto;
        }


        private List<AttendanceClassDateEntity> GenerateClassDates(AttendanceGroupDto item, List<AttendancePlanViewDto> plans)
        {
            DateTime effectiveDate = item.EffectiveDate;
            int dayInMonth = DateTime.DaysInMonth(effectiveDate.Year, effectiveDate.Month);
            int multiple = dayInMonth / item.CycleDays;
            List<AttendanceClassDateEntity> dates = new List<AttendanceClassDateEntity>();
            var latestClassDate = attendanceClassDateData.GetLatestEntityByGroupIdAndEffectiveDate(item.GroupId, item.EffectiveDate).GetAwaiter().GetResult();
            if (latestClassDate.IsNotNull() && DateTime.Parse(string.Format("{0}-{1}-{2}", latestClassDate.Year, latestClassDate.Month, latestClassDate.Day)) == DateTime.Now.Date)
            {
                var newGroup = attendanceGroupData.UpdateEffectiveDateAsync(item.GroupId, DateTime.Now.AddDays(1)).GetAwaiter().GetResult();
                effectiveDate = newGroup.EffectiveDate;
                //重新生成新的日期
                dates = this.AddDates(multiple, effectiveDate, item.CycleDays, plans);
                dates = attendanceClassDateData.InsertListAsync(dates).GetAwaiter().GetResult().ToList();
            }
            else
            {
                #region 生成打卡时间详细列表
                List<AttendanceClassDateEntity> classDateList = attendanceClassDateData.GetDateEntitiesByGroupIdAndEffectiveDate(item.GroupId, effectiveDate).GetAwaiter().GetResult().ToList();
                if (!classDateList.Any())
                {
                    dates = this.AddDates(multiple, item.EffectiveDate, item.CycleDays, plans);
                    dates = attendanceClassDateData.InsertListAsync(dates).GetAwaiter().GetResult().ToList();
                }
                else
                {
                    dates = classDateList;
                }
                #endregion
            }
            return dates;
        }

        private List<AttendanceClassDateEntity> AddDates(int multiple, DateTime effectiveDate, int cycleDays, List<AttendancePlanViewDto> plans)
        {
            var currentLastDayTime = LastDayOfMonth(effectiveDate.Date);
            List<AttendanceClassDateEntity> dates = new List<AttendanceClassDateEntity>();
            for (int i = 0; i < multiple; i++)
            {
                foreach (var plan in plans)
                {
                    var classInfo = attendanceClassData.GetEntityAsync(plan.ClassId).GetAwaiter().GetResult();
                    if (classInfo == null)
                    {
                        throw new ArgumentException($"选择班次:{plan.ClassId} 信息不存在。");
                    }
                    var settings = attendanceClassData.GetAttendanceClassWithSettings(plan.ClassId).GetAwaiter().GetResult();
                    int index = cycleDays * i + Convert.ToInt32(plan.WeekDay);
                    if (index == 1)
                    {
                        foreach (var s in settings)
                        {
                            dates.Add(new AttendanceClassDateEntity
                            {
                                GroupId = plan.GroupId,
                                ClassId = plan.ClassId,
                                ClassName = classInfo.ClassName,
                                Start = s.Start,
                                End = s.End,
                                Year = effectiveDate.Year,
                                Month = effectiveDate.Month,
                                Day = effectiveDate.Day,
                                DayOfWeek = plan.WeekDay,
                                EffectiveDate = effectiveDate
                            });
                        }
                    }
                    else
                    {
                        DateTime settingDate = effectiveDate.AddDays(index - 1).Date;//默认添加了第一天，这里减一日期可连续
                        if (settingDate != currentLastDayTime.Date)
                        {
                            foreach (var s in settings)
                            {
                                dates.Add(new AttendanceClassDateEntity
                                {
                                    GroupId = plan.GroupId,
                                    ClassId = plan.ClassId,
                                    ClassName = classInfo.ClassName,
                                    Start = s.Start,
                                    End = s.End,
                                    Year = settingDate.Year,
                                    Month = settingDate.Month,
                                    Day = settingDate.Day,
                                    DayOfWeek = plan.WeekDay,
                                    EffectiveDate = effectiveDate
                                });
                            }
                        }
                        else
                        {
                            foreach (var s in settings)
                            {
                                dates.Add(new AttendanceClassDateEntity
                                {
                                    GroupId = plan.GroupId,
                                    ClassId = plan.ClassId,
                                    ClassName = classInfo.ClassName,
                                    Start = s.Start,
                                    End = s.End,
                                    Year = currentLastDayTime.Year,
                                    Month = currentLastDayTime.Month,
                                    Day = currentLastDayTime.Day,
                                    DayOfWeek = plan.WeekDay,
                                    EffectiveDate = effectiveDate.Date
                                });
                            }
                            //隔月相差天数
                            var diffDays = cycleDays - Convert.ToInt32(plan.WeekDay);
                            var planWeekDays = plans.Skip(Convert.ToInt32(plan.WeekDay)).Take(diffDays).ToArray();//跳过上一个月排班日期，下一个月从剩余的日期中依次排
                            for (int k = 1; k < diffDays + 1; k++)
                            {
                                var planItem = planWeekDays.Length == 1 ? planWeekDays.First() : plans.First(s => s.WeekDay == planWeekDays[k - 1].WeekDay);
                                var newIndex = index + k;
                                settingDate = effectiveDate.AddDays(newIndex - 1).Date;//默认添加了第一天，这里减一日期可连续
                                settings = attendanceClassData.GetAttendanceClassWithSettings(planItem.ClassId).GetAwaiter().GetResult();
                                foreach (var s in settings)
                                {
                                    dates.Add(new AttendanceClassDateEntity
                                    {
                                        GroupId = plan.GroupId,
                                        ClassId = planItem.ClassId,
                                        ClassName = planItem.ClassName,
                                        Start = s.Start,
                                        End = s.End,
                                        Year = settingDate.Year,
                                        Month = settingDate.Month,
                                        Day = settingDate.Day,
                                        DayOfWeek = planWeekDays.Length == 1 ? planWeekDays.First().WeekDay : planWeekDays[k - 1].WeekDay,
                                        EffectiveDate = effectiveDate
                                    });
                                }
                            }
                            multiple = i;
                            break;
                        }
                    }
                }
            }
            return dates;
        }
        /// <summary>
        /// 获取当前员工所在的考勤组信息
        /// </summary>
        /// <param name="admin"></param>
        /// <returns></returns>
        public AttendanceGroupViewForStaffAppDto GetCurrentAttendanceGroup(AdminDto admin)
        {
            AttendanceGroupViewForStaffAppDto viewDto = new AttendanceGroupViewForStaffAppDto();
            if (!admin.DepartmentId.HasValue)
            {
                throw new ArgumentException("该员工暂时无部门信息。");
            }
            var item = attendanceGroupData.GetEntityByDepartmentIdAndCompanyIdAsync(admin.DepartmentId.Value, admin.CompanyId).GetAwaiter().GetResult().As<AttendanceGroupDto>();
            if (item != null)
            {
                return this.GetByGroupIdForStaffApp(item.GroupId);
            }
            return viewDto;
        }

        #endregion

        #region 公共方法
        /// <summary>
        /// 获取指定的考勤组信息
        /// </summary>
        /// <param name="groupId"></param>
        /// <returns></returns>
        public AttendanceGroupViewDto GetByGroupId(long groupId)
        {
            var entity = this.GetAttendanceGroupViewByGroupId(groupId);
            return entity.As<AttendanceGroupViewDto>();
        }

        /// <summary>
        /// 分页查询考勤组信息
        /// </summary>
        /// <param name="admin">当前登录管理员</param>
        /// <param name="ascending"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="groupName">考勤组名称</param>
        /// <param name="type">考勤类型</param>
        /// <param name="checkInMode">打卡方式</param>
        /// <returns></returns>
        public PageableList<AttendanceGroupViewDto> GetList(AdminDto admin, bool? ascending, int pageIndex, int pageSize, string groupName, AttendanceType? type, CheckInMode? checkInMode)
        {
            var (datas, count) = attendanceGroupData.GetAsync(admin.AdminId, pageIndex, pageSize, ascending.Value, groupName, type, checkInMode).GetAwaiter().GetResult();
            List<AttendanceGroupViewDto> list = new List<AttendanceGroupViewDto>();

            foreach (var item in datas)
            {
                AttendanceGroupViewDto viewDto = new AttendanceGroupViewDto
                {
                    GroupInfo = item.As<AttendanceGroupDto>()
                };
                viewDto.GroupInfo.MemberCount = departmentStaffService.GetStaffCount(item.DepartmentIds);
                switch (item.Type.As<AttendanceType>())
                {
                    case AttendanceType.FIXED:
                        var fixedSettings = attendanceGroupData.GetGroupFixedByGroupId(item.GroupId).GetAwaiter().GetResult().As<List<AttendanceGroupFixedViewDto>>();
                        viewDto.ClassIds.AddRange(fixedSettings.Where(s => s.ClassId > 0).GroupBy(s => s.ClassId).Select(d => d.Key));
                        foreach (var id in viewDto.ClassIds)
                        {
                            var classInfo = attendanceClassData.GetEntityAsync(id).GetAwaiter().GetResult();
                            viewDto.ClassList.Add(string.Format("{0} {1} {2}",
                             string.Join("、", fixedSettings.Where(s => s.ClassId == id).Select(d => d.WeekDay)),
                             classInfo.ClassName,
                             classInfo.WeekDay));
                        }
                        viewDto.ClassList.Add(string.Format("{0} {1}",
                            string.Join("、", fixedSettings.Where(s => s.ClassId == 0).Select(d => d.WeekDay)),
                            "休息"));
                        viewDto.Settings = fixedSettings;
                        break;
                    case AttendanceType.NONE:
                        viewDto.ClassIds.Add(0);
                        viewDto.ClassList.Add("不设置班次，随时打卡");
                        break;
                    case AttendanceType.TURN:
                        var plans = attendanceGroupData.GettGroupPlanByGroupId(item.GroupId).GetAwaiter().GetResult().As<List<AttendancePlanViewDto>>();
                        viewDto.ClassIds.AddRange(plans.Where(s => s.ClassId > 0).GroupBy(s => s.ClassId).Select(d => d.Key));
                        foreach (var id in viewDto.ClassIds)
                        {
                            if (id > 0)
                            {
                                var planItem = plans.First(s => s.ClassId == id);
                                viewDto.ClassList.Add(string.Format("{0} {1}", planItem.ClassName, planItem.ClassWeekDay));
                            }
                        }
                        viewDto.Plans = plans.OrderBy(s => s.WeekDay).ToList();
                        break;
                    default:
                        break;
                }
                list.Add(viewDto);
            }

            return new PageableList<AttendanceGroupViewDto>()
            {
                Count = count,
                Items = list,
                PageIndex = pageIndex,
                PageSize = pageSize
            };
        }

        private AttendanceGroupViewDto GetAttendanceGroupViewByGroupId(long groupId)
        {
            AttendanceGroupViewDto viewDto = new AttendanceGroupViewDto();
            var item = attendanceGroupData.GetEntityAsync(groupId).GetAwaiter().GetResult().As<AttendanceGroupDto>();
            if (item != null)
            {
                viewDto.GroupInfo = item;
                switch (item.Type.As<AttendanceType>())
                {
                    case AttendanceType.FIXED:
                        var fixedSettings = attendanceGroupData.GetGroupFixedByGroupId(groupId).GetAwaiter().GetResult().As<List<AttendanceGroupFixedViewDto>>();
                        viewDto.ClassIds.AddRange(fixedSettings.Where(s => s.ClassId > 0).GroupBy(s => s.ClassId).Select(d => d.Key));
                        foreach (var id in viewDto.ClassIds)
                        {
                            var classInfo = attendanceClassData.GetEntityAsync(id).GetAwaiter().GetResult();
                            viewDto.ClassList.Add(string.Format("{0} {1} {2}",
                             string.Join("、", fixedSettings.Where(s => s.ClassId == id).Select(d => d.WeekDay)),
                             classInfo.ClassName,
                             classInfo.WeekDay));
                        }
                        viewDto.ClassList.Add(string.Format("{0} {1}",
                            string.Join("、", fixedSettings.Where(s => s.ClassId == 0).GroupBy(s => s.ClassId).Select(d => d.First().WeekDay)),
                            "休息"));
                        viewDto.Settings = fixedSettings;
                        break;
                    case AttendanceType.NONE:
                        viewDto.ClassList.Add("不设置班次，随时打卡");
                        break;
                    case AttendanceType.TURN:
                        var plans = attendanceGroupData.GettGroupPlanByGroupId(item.GroupId).GetAwaiter().GetResult().As<List<AttendancePlanViewDto>>();
                        viewDto.ClassIds.AddRange(plans.Where(s => s.ClassId > 0).GroupBy(s => s.ClassId).Select(d => d.Key));
                        foreach (var id in viewDto.ClassIds)
                        {
                            if (id > 0)
                            {
                                var planItem = plans.First(s => s.ClassId == id);
                                viewDto.ClassList.Add(string.Format("{0} {1}", planItem.ClassName, planItem.ClassWeekDay));
                            }
                        }
                        viewDto.Plans = plans.OrderBy(s => s.WeekDay).ToList();
                        break;
                    default:
                        break;
                }
                #region 部门信息

                if (item.DepartmentIds.IsNotNull())
                {
                    string[] departmentIds = item.DepartmentIds.Split(',');
                    foreach (var dptId in departmentIds)
                    {
                        var dpt = departmentService.GetById(Convert.ToInt32(dptId)).GetAwaiter().GetResult();
                        if (dpt != null)
                        {
                            viewDto.Departments.Add(new AttendanceGroupDepartmentDto
                            {
                                DepartmentId = dpt.DepartmentId,
                                DepartmentName = dpt.DepartmentName,
                                ParentDepartmentId = dpt.ParentDepartmentId,
                                CompanyId = dpt.CompanyId
                            });
                        }
                    }
                }
                #endregion
                #region 人员信息

                if (item.ManagerIds.IsNotNull())
                {
                    string[] managerIds = item.ManagerIds.Split(',');
                    foreach (var adminId in managerIds)
                    {
                        var admin = adminService.GetAdminInfoByAdminId(Convert.ToInt64(adminId));
                        if (admin != null)
                        {
                            viewDto.Managers.Add(new AttendanceGroupAdminDto
                            {
                                AdminId = admin.AdminId,
                                FullName = admin.FullName,
                                CompanyId = admin.CompanyId,
                                CompanyName = admin.CompanyName
                            });
                        }
                    }
                }
                if (item.IgnoreMemberIds.IsNotNull())
                {
                    string[] ignoreMember = item.IgnoreMemberIds.Split(',');
                    foreach (var adminId in ignoreMember)
                    {
                        var admin = adminService.GetAdminInfoByAdminId(Convert.ToInt64(adminId));
                        if (admin != null)
                        {
                            viewDto.IgnoreManagers.Add(new AttendanceGroupAdminDto
                            {
                                AdminId = admin.AdminId,
                                FullName = admin.FullName,
                                CompanyId = admin.CompanyId,
                                CompanyName = admin.CompanyName
                            });
                        }
                    }
                }
                #endregion

                #region 打卡方式

                if (item.ModeIds.IsNotNull())
                {
                    string[] modes = item.ModeIds.Split(',');
                    AttendanceModeViewDto modeView = new AttendanceModeViewDto();
                    foreach (var mode in modes)
                    {
                        if (mode.ToString() == CheckInMode.Location.ToString())
                        {
                            modeView.Locations = attendanceLocationService.GetListByModeIdAndGroupId(item.GroupId);

                        }
                        if (mode.ToString() == CheckInMode.Wifi.ToString())
                        {
                            modeView.WifiList = attendanceWiFiService.GetListByModeIdAndGroupId(item.GroupId);
                        }

                        viewDto.Modes = modeView;
                    }
                }

                #endregion
                #region 补卡规则信息
                viewDto.RemedyRule = remedyRulesService.GetById(item.RemedyRuleId);
                #endregion
            }
            return viewDto;

        }
        #endregion

        #endregion
    }
}

